package com.spotmanger.project.modular.spotfile.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spotmanger.project.common.core.utils.DateUtils;
import com.spotmanger.project.common.core.utils.file.FileUploadUtils;
import com.spotmanger.project.core.Constants;
import com.spotmanger.project.modular.spotfile.entity.EasyfileChunk;
import com.spotmanger.project.modular.spotfile.entity.EasyfileEntity;
import com.spotmanger.project.modular.spotfile.mapper.EasyfileEntityMapper;
import com.spotmanger.project.modular.spotfile.service.IEasyfileChunkService;
import com.spotmanger.project.modular.spotfile.service.IEasyfileService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.*;

/**
 * @author leihao
 * @version 1.0
 * @date 2020年12月24日
 * @description
 */
@Service
@Slf4j
public class EasyfileServiceImpl extends ServiceImpl<EasyfileEntityMapper, EasyfileEntity> implements IEasyfileService {

    @Resource
    IEasyfileChunkService easyfileChunkService;

    @Override
    @Transactional
    public EasyfileChunk easyfileUpload(MultipartFile chunkFile, EasyfileChunk easyfileChunk, String baseDir) {
        //检测分片是否已上传
        Boolean isExist = this.checkChunkIsExist(easyfileChunk);
        if (isExist) {
            return this.easyfileChunkIsExist(easyfileChunk);
        }
        return this.easyfileChunkNoExist(chunkFile, easyfileChunk, baseDir);
    }

    @Override
    @Transactional
    public EasyfileEntity easyfileMerge(EasyfileChunk easyfileChunk, String baseDir) {
        EasyfileEntity easyfileEntity = null;
        String fileSuffix = FilenameUtils.getExtension(easyfileChunk.getFileName()).toLowerCase();
        String fileName = FileUploadUtils.encodingFilename(easyfileChunk.getFileName());
        fileName = StringUtils.isNotEmpty(fileSuffix) ? (fileName + "." + fileSuffix) : fileName;
        String filePath = DateUtils.datePath() + File.separator + fileName;

        Map<String, Object> columnMap = new HashMap<>();
        columnMap.put("file_id", easyfileChunk.getFileId());
        List<EasyfileChunk> chunks = easyfileChunkService.getBaseMapper().selectByMap(columnMap);
        if (!chunks.isEmpty()) {
            Boolean result = this.mergeEasyFileChunk(baseDir, filePath, chunks);
            if (result) {//分片合并成功
                easyfileEntity = new EasyfileEntity();
                easyfileEntity.setFileName(fileName);
                easyfileEntity.setFilePath(filePath);
                easyfileEntity.setStatus(Constants.NORMAL);
                easyfileEntity.setOriginalName(easyfileChunk.getFileName());
                easyfileEntity.setFileSize(easyfileChunk.getFileSize());
                easyfileEntity.setFileSuffix(fileSuffix);
                easyfileEntity.setFileType(easyfileChunk.getFileType());
                easyfileEntity.setTbbh(easyfileChunk.getTbbh());
                this.getBaseMapper().insert(easyfileEntity);
            }
        }
        return easyfileEntity;
    }

    @Override
    @Transactional
    public void removeEasyfileChunk(EasyfileChunk easyfileChunk) {
//		jpaDao.delete("delete from EasyfileChunk where fileId = ?", easyfileChunk.getFileId());
    }

    @Override
    public EasyfileEntity selectEasyfileEntityById(String id) {
        return this.getBaseMapper().selectById(id);
    }

    @Override
    @Transactional
    public void deleteEasyfileEntityByIds(String[] ids) {
        for (String id : ids) {
            this.getBaseMapper().deleteById(id);
        }
    }

    /**
     * 检查分片是否已上传
     *
     * @param easyfileChunk
     * @return
     */
    private Boolean checkChunkIsExist(EasyfileChunk easyfileChunk) {
        Map<String, Object> columnMap = new HashMap<>();
        columnMap.put("file_id", easyfileChunk.getFileId());
        List<EasyfileChunk> chunks = easyfileChunkService.getBaseMapper().selectByMap(columnMap);
        return !chunks.isEmpty();
    }

    /**
     * 分片已上传
     *
     * @param easyfileChunk
     * @return
     */
    private EasyfileChunk easyfileChunkIsExist(EasyfileChunk easyfileChunk) {
        LambdaQueryWrapper<EasyfileChunk> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(EasyfileChunk::getFileId, easyfileChunk.getFileId());
        List<EasyfileChunk> easyfileChunks =  easyfileChunkService.list(queryWrapper);
        if(!easyfileChunks.isEmpty()){
            EasyfileChunk maxEasyfileChunk = easyfileChunks.stream().max(Comparator.comparingInt(EasyfileChunk ::getChunk)).get();
            easyfileChunk.setChunk(maxEasyfileChunk.getChunk());
        }

        return easyfileChunk;
    }

    /**
     * 分片上传不存在
     *
     * @param chunkFile
     * @param easyfileChunk
     * @param baseDir
     * @return
     */
    private EasyfileChunk easyfileChunkNoExist(MultipartFile chunkFile, EasyfileChunk easyfileChunk, String baseDir) {
        String chunkPath = FileUploadUtils.chunkFilename(easyfileChunk.getChunkID());
        try {
            File file = FileUploadUtils.getAbsoluteFile(baseDir, chunkPath);
            chunkFile.transferTo(file);
        } catch (IOException e) {
            String msg = "【" + easyfileChunk.getFileName() + "】第" + (easyfileChunk.getChunk() + 1) + "分片文件上传失败";
            log.error(msg, e);
        }
        easyfileChunk.setChunkPath(chunkPath);
        easyfileChunkService.save(easyfileChunk);
        return easyfileChunk;
    }

    /**
     * 合并分片文件
     *
     * @param baseDir
     * @param filePath
     * @param chunks
     * @return true==success; false=failed
     */
    private Boolean mergeEasyFileChunk(String baseDir, String filePath, List<EasyfileChunk> chunks) {
        RandomAccessFile writer = null, reader = null;
        try {
            File file = FileUploadUtils.getAbsoluteFile(baseDir, filePath);
            writer = new RandomAccessFile(file, "rw");

            for (int i = 0; i < chunks.size(); i++) {
                File chunkFile = FileUploadUtils.getAbsoluteFile(baseDir, chunks.get(i).getChunkPath());
                reader = new RandomAccessFile(chunkFile, "r");
                byte[] b = new byte[1024];
                int line = 0;
                while ((line = reader.read(b)) != -1) {//先读后写
                    writer.write(b, 0, line);
                }
            }

            return true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return false;
    }

}
